package server;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket;

import common.Lector_socket;
import common.Mensaje;


public class ThreadServerAndroid extends Thread{
	private static final int TIME_OUT_CIERRE= 3000;
	@SuppressWarnings("unused")
	private static final int TIME_OUT_SOCKET = 1300; // timeout para socket

	private SSLSocket conexion_entrante;
	private ServidorPrincipal server;
	private Lector_socket lector;
	private int estado_interno;
	private String fingerprint;

	private boolean fin;

	private boolean notificado_por_hay_tema;

	private Mensaje[] ultimoIntercambio;

	public final static int PREGUNTA =0;
	public final static int RESPUESTA =1;

	private Log log;
	private boolean flag_se_verifico_imei;
	private String nombre;

	private boolean emitioVoto;


	public ThreadServerAndroid(SSLSocket s, ServidorPrincipal ts, String fp, Log l){
		emitioVoto=false;
		log = l;
		conexion_entrante = s;
		server=ts;
		lector = new Lector_socket(conexion_entrante);
		estado_interno = server.get_estado();
		fingerprint=fp;
		ultimoIntercambio=new Mensaje[2];
		notificado_por_hay_tema=false;
		flag_se_verifico_imei = false;
		nombre=obtenerCommonName(s);

	}

	public void run(){
		
		fin=server.get_fin_sesion();// habria que considerar si el cliente termina la sesi�n...
		while(!fin){

			Mensaje msj = lector.leer_msj();

			if(msj!=null){ // es decir, si no se cerr� la conexi�n
				Mensaje rta = new Mensaje();

				estado_interno = server.get_estado();
				switch(estado_interno){
				case 0:{
					break;
				}
				case 1:{
					// a�n no inici� sesi�n, se le responde con NO ante SALUDO
					if(msj.getTipo_msj().equals(Mensaje.TIPO_SALUDO)){
						rta.setTipo_msj(Mensaje.TIPO_NO);

						if(!flag_se_verifico_imei){
							String imei_recibido = msj.getContenido();
							boolean imei_valido = verificacionIMEI(imei_recibido);
							if(!imei_valido){
								server.removerClienteImeiInvalido(fingerprint, this);
								fin=true;
								String msj_log = "El imei "+imei_recibido+" del cliente "+fingerprint+" NO es válido";
								log.writeLog(Log.WARNING, "CLIENTE ANDROID", "Verificacion IMEI", msj_log);
								rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);

							}
						}
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_SALIR)){
						rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
						fin = true;
					}else{
						rta.setTipo_msj(Mensaje.TIPO_ERROR);
					}
					break;
				}
				case 2:{
					// recibe un saludo del cliente - se le le responde con SI
					if(msj.getTipo_msj().equals(Mensaje.TIPO_SALUDO)){
						rta.setTipo_msj(Mensaje.TIPO_SI);
						if(!flag_se_verifico_imei){
							String imei_recibido = msj.getContenido();
							boolean imei_valido = verificacionIMEI(imei_recibido);
							if(!imei_valido){
								server.removerClienteImeiInvalido(fingerprint, this);
								fin=true;
								String msj_log = "El imei "+imei_recibido+" del cliente "+fingerprint+" NO es válido";
								log.writeLog(Log.WARNING, "CLIENTE ANDROID", "Verificacion IMEI", msj_log);
								rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);

							}
						}
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_SALIR)){
						rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
						fin = true;
					}else{
						rta.setTipo_msj(Mensaje.TIPO_ERROR);
					}
					break;
				}
				case 3:{
					notificado_por_hay_tema=false;
					// a�n no hay tema, le contesta que NO
					if(msj.getTipo_msj().equals(Mensaje.TIPO_HAY_TEMA)){
						rta.setTipo_msj(Mensaje.TIPO_NO);
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_HAY_NUEVO_TEMA)){
						rta.setTipo_msj(Mensaje.TIPO_SI);
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_SALIR)){
						rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
						fin = true;
					}else{
						rta.setTipo_msj(Mensaje.TIPO_ERROR);
					}
					break;
				}
				case 4:{
					// el cliente pregunta si hay tema, responde que s�
					emitioVoto=false;
					rta = new Mensaje();
					// si el msj del cliente es "hay votaci�n" le responde no, porque a�n no comenzo el periodo de tiempo para la votaci�n
					// caso contrario responde que s� (asumimos que es un msj preguntando por "hay tema")
					if(msj.getTipo_msj().equals(Mensaje.TIPO_HAY_TEMA)){
						rta.setTipo_msj(Mensaje.TIPO_SI);
						rta.setContenido(server.obtenerTemaActual());

						notificado_por_hay_tema=true;
						synchronized (server) {
							server.notify(); // despierto al server para anunciar que hubo una votaci�n correcta (as� verifica si todos votaron)
						}

					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_HAY_VOTACION)){
						rta.setTipo_msj(Mensaje.TIPO_NO);
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_SALIR)){
						rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
						fin = true;
					}else{
						rta.setTipo_msj(Mensaje.TIPO_ERROR);
					}
					break;
				}
				case 5:{
					// recibe votos del cliente y va contando, cuando recibe �tlimo voto cambia a estado 6
					// env�a confinrmacion
					if(msj.getTipo_msj().equals(Mensaje.TIPO_HAY_VOTACION)){
						rta.setTipo_msj(Mensaje.TIPO_SI);
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_VOTO)){

						// enviar voto al server ppal
						boolean se_registro_voto = server.enviarVoto(msj.getContenido(), fingerprint);
						rta.setTipo_msj(Mensaje.TIPO_OK);

						if(se_registro_voto){
							emitioVoto=true;
							synchronized (server) {
								server.notify(); // despierto al server para anunciar que hubo una votaci�n correcta (as� verifica si todos votaron)
								rta.setContenido("Su voto <<"+msj.getContenido()+">> fue recibido de forma correcta.");
							}


						}else{
							rta.setContenido("Su voto no fue registrado");
						}

					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_SALIR)){
						rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
						fin = true;
					}else{
						rta.setTipo_msj(Mensaje.TIPO_ERROR);
					}
					break;
				}

				case 6:{

					if(msj.getTipo_msj().equals(Mensaje.TIPO_HAY_TEMA)){
						rta.setTipo_msj(Mensaje.TIPO_NO);
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_SALIR)){
						rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
						fin = true;
					}else{
						rta.setTipo_msj(Mensaje.TIPO_ERROR);
					}
					break;
				}
				case 7:{
					// esperando que admin se decida a continuar con otro tema o cierre sesion
					// a�n no hay tema nuevo, le contesta que NO
					if(msj.getTipo_msj().equals(Mensaje.TIPO_HAY_NUEVO_TEMA)){
						rta.setTipo_msj(Mensaje.TIPO_NO);
					}else if(msj.getTipo_msj().equals(Mensaje.TIPO_SALIR)){
						rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
						fin = true;
					}else{
						rta.setTipo_msj(Mensaje.TIPO_ERROR);
					}
					break;
				}
				case 8:{
					rta.setTipo_msj(Mensaje.TIPO_CIERRE_SESION);
					fin = true;
					break;
				}


				} // end -switch

				lector.enviar_msj(rta);

				ultimoIntercambio[PREGUNTA] = msj;
				ultimoIntercambio[RESPUESTA] = rta;

			}else{ // else de if(msj!=null) (se cerr� la conexi�n abruptamente)
				fin = true;
			} 
		} // end - while

		cerrarThread();
	}

	/**
	 * VER SU FUNCIONA BIEN!!!!!!!!!!!!!!!!
	 * @return
	 */
	public boolean clienteEstaConectado(){
		return !fin;
	}
	public String obtenerFingerprint(){
		return fingerprint;
	}
	private void cerrarThread(){
		// sleep para dar tiempo a que cliente reciba la rta
		try {
			sleep(TIME_OUT_CIERRE);
		} catch (InterruptedException e) {
		}

		// cierre de conexion
		lector.cerrar();
		try {
			conexion_entrante.close();
		} catch (IOException e) {
		}
		log.writeLog(Log.INFO, "CLIENTE ANDROID", "Cerrar conexión", "Se cerró la conexión del cliente "+fingerprint);
	}

	public synchronized Mensaje[] obtenerUltimoIntercambio(){
		return ultimoIntercambio;
	}

	public synchronized boolean notificadoPorHayTema(){
		return notificado_por_hay_tema;
	}

	private boolean verificacionIMEI(String imei){
		boolean verificacion = server.verificarIMEI(fingerprint, imei);
		flag_se_verifico_imei = true;
		return verificacion;
	}

	private  String obtenerCommonName(SSLSocket socket){
		// convenci�n para el CN=<nombre-apellido-rol>
		String nombre=null;
		try {
			String commonName=conexion_entrante.getSession().getPeerPrincipal().getName();
			Pattern p = Pattern.compile("<(.*)-(.*)-(.*)>");
			Matcher m = p.matcher(commonName);
			if (m.find()){
				nombre=m.group(1)+" "+m.group(2);
			}
		} catch (SSLPeerUnverifiedException e) {
			System.err.println(e.getMessage());
		}
		return nombre;
	}
	public String getNombre(){
		return nombre;
	}
	public boolean emitioVoto(){
		return emitioVoto;
	}

}
